/**
 * @FileName: CmccPackageService.java
 * @Author
 * @Description:
 * @Date 2016年5月26日 上午9:25:46
 * @CopyRight ZTE Corporation
 */
package cn.hpclub.server.service;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.hpclub.server.ccbpay.ServiceType;
import cn.hpclub.server.model.CmccOrder;
import cn.hpclub.server.plugin.Ssdb;

public class CmccPackageService{
    private static final Logger      logger  = LoggerFactory.getLogger(CmccPackageService.class);

    public static CmccPackageService service = new CmccPackageService();

    /**
     * @Title: updatePackageOrder
     * @Description:实现更新订单支付状态流程，返回是否去办理业务结果。 该方法因建行对同一个order发送三次notify，
     *                                        而且有时几乎是同时 ，因此需要做互斥。目前由DB去做互斥，
     *                                        根据DB结果canMkPackage来进行业务处理 。
     *                                        保证只有一个notify会去办理业务。
     *                                        修改本方法时，请务必熟知内部逻辑。
     * @param orderId
     * @param amount
     * @param result
     * @return boolean
     */
    public boolean updatePackageOrder(String orderId, String amount, boolean result){
        boolean canMkPackage = false;
        try{
            int payStatus = result ? CmccOrder.PAID : CmccOrder.FAILED;
            if(payStatus == CmccOrder.PAID){
                // 支付成功
                // 未付/失败->成功，写DB(写DB失败，不办理业务，以免后续多次办理业务)，写成功，若金额相同，办理业务，金额不同，则不办理业务；成功->成功，不写DB，不办理业务。

                // 利用DB进行同步控制。多个notify只有一个会去写数据库。
                canMkPackage = CmccOrder.dao.updatePayStatusSuc(orderId, payStatus, new Date(), "更新支付状态",
                                                                Double.valueOf(amount));
                // 互斥的情况下，保证同一个orderid只有一个notify会去判断金额是否正确。
                if(canMkPackage){
                    logger.info("first time suc-msg");
                    // 若是金额不同，执行完上面的更新表格后，返回false，不去办理业务。避免被攻击办理了业务。
                    if(amountIncorrect(orderId, amount, canMkPackage)){
                        canMkPackage = false;
                    }

                } else{
                    // 已办理过业务
                    logger.info("package business already done");
                }

            } else{
                // 未付->失败，写DB，不论写DB成功与否，都不办业务；失败->失败，不写DB,不办业务；成功->失败，不写DB，不办业务，以免成功-失败-成功，导致多次办理业务。
                logger.info("pay failed.order:" + orderId);
                CmccOrder.dao.updatePayStatusFailed(orderId, payStatus, new Date(), "支付失败", Double.valueOf(amount));
                canMkPackage = false;
            }

        }
        catch(Exception e){
            logger.error("update package order exception，order ID:" + orderId + ",amount:" + amount + ",result:"
                    + result);
            // 更新出现异常时，请返回false
            canMkPackage = false;
            e.printStackTrace();
        }
        finally{
            // 不管成功还是失败，都些SSDB，保存原始记录。
            saveSsdb(ServiceType.PACKAGE, orderId, amount, result);
        }

        logger.info("updatePackageOrder canMkPackage = " + canMkPackage);
        return canMkPackage;
    }

    /**
     * @Title: amountCorrect
     * @Description:TODO
     * @param orderId
     * @param amount
     * @param canMkPackage
     * @return boolean
     */

    private boolean amountIncorrect(String orderId, String amount, boolean canMkPackage){
        CmccOrder order = CmccOrder.dao.getOrderInfo(orderId);
        Double orderAmount = order.getDouble(CmccOrder.ORDER_AMOUNT);
        Double paidAmount = Double.valueOf(amount);
        logger.info("orderid:" + orderId + ",orderAmount:" + orderAmount + ",paidAmount:" + paidAmount);
        if(Double.compare(paidAmount, orderAmount) < 0){
            logger.error("paid error.amount is not corrent." + "orderid:" + orderId + ",orderAmount:" + orderAmount
                    + ",paidAmount:" + paidAmount);
            return true;
        }
        return false;
    }

    private void saveSsdb(ServiceType type, String orderId, String amount, boolean result){
        try{
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd");
            String dateString = simpleDateFormat.format(new Date());

            SimpleDateFormat simpleDateFormat2 = new SimpleDateFormat("HH:mm:ss");
            String timeString = simpleDateFormat2.format(new Date());

            Map<String, String> infos = new HashMap<>();
            infos.put("no", orderId);
            infos.put("total", amount);
            infos.put("status", result ? "Y" : "N");
            infos.put("time", timeString);
            if(type == ServiceType.RECHARGE){
                Ssdb.use().hset("recharge" + dateString, orderId, infos);
            } else if(type == ServiceType.PACKAGE){
                Ssdb.use().hset("package" + dateString, orderId, infos);
            }
        }
        catch(Exception e){
            logger.error("save pay record to ssdb failed.service type:" + type + ",orderid:" + orderId + ",amount:"
                    + amount + ",result:" + result);
            e.printStackTrace();
        }

    }

}
